package com.yoyo.itravel.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;

/**
 * @Description 解决全站乱码问题，处理所有的请求
 *
 * @author HZX
 * @date 2020/5/2 21:48
 */
@WebFilter("/*")
public class CharacterFilter implements Filter {

    private String encoding; // 编码名称

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 获得配置的编码参数，并给成员变量encoding赋值
        this.encoding = filterConfig.getInitParameter("encoding");
        // 如果没有配置，则使用默认的编码
        this.encoding = this.encoding == null ? "UTF-8" : this.encoding;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse rep, FilterChain filterChain) throws IOException, ServletException {
        //将父接口转为子接口
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) rep;

        // 构建一个自定义的request对象
        MyRequest myRequest = new MyRequest(request, encoding);

        //处理响应乱码
        response.setContentType("text/html;charset=" + encoding);
        // 处理后，放行
        filterChain.doFilter(myRequest,response);
    }

    @Override
    public void destroy() {

    }
}

/**
 * @Description 使用装饰器设计模式--重写request的方式得到参数的值（解决GET请求中文数据乱码问题）
 *              1.实现/继承一个与包装对象相同的接口/类
 *              2.定义一个包装类对象相同的引用
 *              3.定义一个构造方法，把被包装的对象的引用传入
 *              4.对于不需要的方法，直接调用
 *              5.对于需要的方法，进行改写操作
 *
 * @author HZX
 * @date 2020/5/9 16:32
 */
class MyRequest extends HttpServletRequestWrapper {

    private HttpServletRequest request;
    private String encoding;
    private boolean isEnocode = true; // 判断是否需要进行GET方式编码

    public MyRequest(HttpServletRequest request, String encoding) {
        super(request);
        this.request = request;
        this.encoding = encoding;
    }

    @Override
    public String getAuthType() {
        return super.getAuthType();
    }

    @Override
    public String getParameter(String name) {
        // 获得name所对应的所有值
        String[] values = getParameterValues(name);
        // 判断values是否为null，如果不为null则直接返回第一个值
        return values == null ? null : values[0];
    }

    @Override
    public String[] getParameterValues(String name) {
        // 获得所有的参数--键值对
        Map<String, String[]> parameterMap = getParameterMap();

        // 判断parameterMap是否为null
        if (parameterMap == null) {
            // 如果为null，直接返回null
            return null;
        }

        // 通过name获得name所对应的值，并返回
        return parameterMap.get(name);
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        //获取请求方法
        String method = request.getMethod();

       try {
           if("POST".equalsIgnoreCase(method)){
               // 解决POST请求中文数据乱码问题
               request.setCharacterEncoding(this.encoding);
           } else if ("GET".equalsIgnoreCase(method)) {
                // 得到所有的键值对
               Map<String, String[]> map = this.request.getParameterMap();

               if (isEnocode) {
                   // 遍历所有的值，进行编码转换
                   for (Map.Entry<String, String[]> entry : map.entrySet()) {
                       // 获得value
                       String[] values = entry.getValue();

                       if (values == null || values.length == 0) {
                           continue;
                       }

                       // 遍历value数组
                       for (String value : values) {
                           // 在进行GET请求时，浏览器是先用"UTF-8"进行编码，然后再用"ISO-8859-1"进行编码（为了减少中文使用的字节数--"ISO-8859-1"一个中文两个字节）
                           // 对获得的值进行解码处理
                           value = new String(value.getBytes("ISO-8859-1"), encoding);
                       }
                   }

                   // 修改标识符
                   isEnocode = false;
               }

               // 返回map集合
               return map;
           }
       } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
       }
        // 其他请求方式，不做任何处理
        return super.getParameterMap();
    }

}
